# 模块使用
import os
import time
import json
import threading
import websocket
import websocket_server

# 外部引用
try:
    from werkzeug._reloader import run_with_reloader
except:
    pass

# 自身调用
from .app import bot
from .config import config
from .notice_request import *
from .parse_handler import parse, parse_invoke
from .plugin import load_plugins
from .util import jsonify

bot.config = config
bot.jsonify = jsonify

__version__ = '5.1.0'
__description__ = 'lovely cat >= 5.0'

class SingletonType(type):
    _instance_lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType, cls).__call__(*args, **kwargs)
        return cls._instance

class InvokeServer(threading.Thread):
    def run(self):
        print('开始创建ws服务器, port:', config.self_server_port)
        bot.server = websocket_server.WebsocketServer(config.self_server_port, "0.0.0.0")
        bot.server.set_fn_new_client(self.client_enter)
        bot.server.set_fn_client_left(self.client_left)
        bot.server.set_fn_message_received(self.msg_received)
        bot.server.run_forever()

    def client_enter(self, client, server):
        print('客户', client['id'], '进入了')

    def client_left(self, client, server):
        print('客户', client['id'], '退出了')

    def msg_received(self, client, server, raw_info):
        try:
            info = json.loads(raw_info)
            if info.get('event') == 'invoke':
                print(info)
                threading.Thread(target=parse_invoke, args=(client, server, info)).start()
        except Exception as e:
            msg = f'invoke 的内容格式不正确哦, {e}'
            print(msg)
            bot.server.send_message(client, msg)

class CreateBot(threading.Thread, metaclass=SingletonType):
    def __init__(self, root_path='.', plugin_dirs=['plugins'], enable_invoke=False):
        threading.Thread.__init__(self)
        self.root_path = root_path
        self.bot_ip = config.get('bot_ip', '127.0.0.1')
        self.bot_server_port = config.get('bot_server_port', 10001)
        self.reconnect_interval = config.get('reconnect_interval', 10)

        self.connect_server()
        self.open_invoke(enable_invoke)
        self.init_notice_request()
        self.regist_plugin(plugin_dirs)

    def connect_server(self):
        print('开始连接ws服务器, port:', self.bot_server_port)
        while True:
            try:
                bot.client = websocket.create_connection(f'ws://{self.bot_ip}:{self.bot_server_port}/websocket')
                print('连接成功')
                break
            except ConnectionRefusedError:
                print(f'无法连接到ws服务器, {self.reconnect_interval} 秒后重新尝试连接')
                time.sleep(self.reconnect_interval)

    @staticmethod
    def open_invoke(enable_invoke):
        if enable_invoke:
            bot.server = InvokeServer()
            bot.server.start()

    def init_notice_request(self):
        arg_type = bot.config.get('arg_type', 'list')
        cmd_type = bot.config.get('cmd_type', 'constant')
        bot.on_command = on_command(arg_type, cmd_type)
        bot.on_notice = on_notice()
        bot.on_request = on_request()
        bot.on_invoke = on_invoke()
        bot.on_env = on_env()

    def regist_plugin(self, plugin_dirs):
        for plugin_dir in plugin_dirs:
            plugin_dir = os.path.normpath(plugin_dir)
            module_prefix = plugin_dir.replace(os.sep, '.')
            load_plugins(plugin_dir, module_prefix)

    def run(self):
        print('等待命令解析')
        error_msg = None
        while True:
            try:
                info = json.loads(bot.client.recv())
                if info.get('event') != 'send_out_msg' or getattr(config, 'print_send_out_msg', False):
                    print('\n\n收到消息:')
                    if not getattr(config, 'print_json_msg', False) and 'json_msg' in info:
                        print_info = {k: v for k, v in info.items() if 'key' != 'json_msg'}
                    else:
                        print_info = info # {k: v for k, v in info.items()}
                    if getattr(config, 'pretty_msg', False):
                        print(json.dumps(print_info, indent='    '))
                    else:
                        print(print_info)
                threading.Thread(target=parse, args=(info,)).start()
            except ConnectionRefusedError:
                error_msg = '无法连接到ws服务器'
            except ConnectionResetError:
                error_msg = '连接断开'

            if error_msg:
                print(f'{error_msg}, {self.reconnect_interval} 秒后重新尝试连接')
                time.sleep(self.reconnect_interval)
                try: 
                    bot.client = websocket.create_connection(f'ws://{self.bot_ip}:{self.bot_server_port}/websocket')
                    print('连接成功')
                except: pass

